package com.cyj.dream.captcha.util;

import cn.hutool.core.util.NumberUtil;
import com.cyj.dream.captcha.callback.CacheCallback;
import com.cyj.dream.captcha.constant.CacheConstant;
import com.cyj.dream.captcha.core.CaptchaResult;
import com.cyj.dream.captcha.core.CaptchaVo;
import com.cyj.dream.captcha.core.PuzzleCaptcha;
import com.cyj.dream.captcha.core.PuzzleGifCaptcha;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.MultiValueMap;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 验证码工具类
 * @BelongsProject: DreamChardonnay
 * @BelongsPackage: com.cyj.dream.captcha.util
 * @Author: ChenYongJia
 * @CreateTime: 2021-09-27 10:15
 * @Email: chen87647213@163.com
 * @Version: 1.0
 */
@Slf4j
public class CaptchaUtil {


    private static final int X_OFFSET = 8;

    private static final int SPEED = 500;


    /**
     * 获取验证码
     *
     * @return
     */
    public static CaptchaVo captcha(PuzzleCaptcha puzzleCaptcha, String requestedSessionId, CacheCallback cacheCallback) {
        String id = requestedSessionId;
        // 删除上次验证结果
        cacheCallback.removeCache(CacheConstant.CAPTCHA_RESULT + id);

        Map<String, Object> cacheMap = new HashMap<>();
        CaptchaVo captchaVo = new CaptchaVo();
        captchaVo.setImage1(ImageConvertUtil.toDataUri(puzzleCaptcha.getArtwork(), "png"));
        captchaVo.setImage2(ImageConvertUtil.toDataUri(puzzleCaptcha.getVacancy(), "png"));

        // 偏移量
        cacheMap.put("x", puzzleCaptcha.getX());
        cacheMap.put("time", System.currentTimeMillis());
        cacheMap.put("width", puzzleCaptcha.getWidth());
        cacheCallback.putCache(CacheConstant.CAPTCHA + id, cacheMap, 5 * 60, TimeUnit.SECONDS);
        return captchaVo;
    }

    /**
     * 获取验证码(gif)
     *
     * @return
     */
    public static CaptchaVo captcha(PuzzleGifCaptcha puzzleCaptcha, String requestedSessionId, CacheCallback cacheCallback) {
        String id = requestedSessionId;
        // 删除上次验证结果
        cacheCallback.removeCache(CacheConstant.CAPTCHA_RESULT + id);

        Map<String, Object> cacheMap = new HashMap<>();
        CaptchaVo captchaVo = new CaptchaVo();
        captchaVo.setImage1(ImageConvertUtil.toDataUri(puzzleCaptcha.getArtwork().toByteArray(), "png"));
        captchaVo.setImage2(ImageConvertUtil.toDataUri(puzzleCaptcha.getVacancy().toByteArray(), "png"));

        // 偏移量
        cacheMap.put("x", puzzleCaptcha.getX());
        cacheMap.put("time", System.currentTimeMillis());
        cacheMap.put("width", puzzleCaptcha.getWidth());
        cacheCallback.putCache(CacheConstant.CAPTCHA + id, cacheMap, 5 * 60, TimeUnit.SECONDS);
        return captchaVo;
    }

    /**
     * 验证码验证
     *
     * @param map
     * @return
     */
    public static CaptchaResult verify(Map<String, Object> map, String requestedSessionId, CacheCallback cacheCallback) {
        String id = requestedSessionId;
        CaptchaResult result = new CaptchaResult();
        result.setSuccess(false);

        String key = CacheConstant.CAPTCHA + id;
        // 偏移量
        Integer vx = StrUtil.toInt(map.get("x"));
        // 宽度
        Integer width = StrUtil.toInt(map.get("width"), 1);
        return checkResult(id, vx, width, key, cacheCallback);
    }


    public static CaptchaResult verify(MultiValueMap<String, String> map, String requestedSessionId, CacheCallback cacheCallback) {
        String id = requestedSessionId;


        String key = CacheConstant.CAPTCHA + id;
        // 偏移量
        Integer vx = StrUtil.toInt(map.getFirst("x"));
        // 宽度
        Integer width = StrUtil.toInt(map.getFirst("width"), 1);
        return checkResult(id, vx, width, key, cacheCallback);
    }

    private static CaptchaResult checkResult(String id, Integer vx, Integer width, String key, CacheCallback cacheCallback) {
        CaptchaResult result = new CaptchaResult();
        result.setSuccess(false);
        //获取到缓存
        Map<String, Object> cacheMap = cacheCallback.getCache(key);
        if (cacheMap == null) {
            return result;
        }
        Integer x = StrUtil.toInt(cacheMap.get("x"));
        Integer realWidth = StrUtil.toInt(cacheMap.get("width"));
        Long time = StrUtil.toLong(cacheMap.get("time"));
        long s = System.currentTimeMillis() - time;

        // 查看前端的缩放比例
        double ratio = NumberUtil.div(realWidth, width).doubleValue();

        if (x == null || vx == null) {
            cacheCallback.removeCache(key);
            return result;
        } else if (Math.abs(x - (vx * ratio)) > X_OFFSET * ratio || s < SPEED) {
            cacheCallback.removeCache(key);
            return result;
        }
        result.setSuccess(true);
        cacheCallback.removeCache(key);
        cacheCallback.putCache(CacheConstant.CAPTCHA_RESULT + id, result, 5 * 60, TimeUnit.SECONDS);
        return result;
    }

}
